/**
 * 
 */
package ru.amse.stroganova.ui.command;

import java.awt.Point;
import java.util.HashMap;
import java.util.Map;

import ru.amse.stroganova.presentation.GraphPresentation;
import ru.amse.stroganova.presentation.VertexPresentation;
import ru.amse.stroganova.ui.layout.Layout;
import ru.amse.stroganova.ui.layout.PredefinedLayout;
import ru.amse.stroganova.ui.visual.GraphElementSelection;

class DragCommand implements Command {
	
	private final GraphPresentation graphPresentation;
	
	private final GraphElementSelection graphSelection;

	private final Layout newLayout;
	
	private final Layout oldLayout;

	Map<VertexPresentation, Point> afterDragPositions;

	Map<VertexPresentation, Point> beforeDragPositions;

	private boolean isFirstTime;

	/**
	 * Creates new DragCommand.
	 * 
	 * @param start
	 *            start point
	 * @param end
	 *            end point
	 * @param graphPresentation 
	 * @param graphSelection 
	 */
	public DragCommand(Point start, Point end, GraphPresentation graphPresentation, GraphElementSelection graphSelection) {
		this.graphSelection = graphSelection;
		this.graphPresentation = graphPresentation;
		afterDragPositions = new HashMap<VertexPresentation, Point>();
		for (VertexPresentation vp : graphSelection.getSelectedVertices()) {
			afterDragPositions.put(vp, vp.getCenter());
		}
		newLayout = new PredefinedLayout(afterDragPositions);
		
		beforeDragPositions = new HashMap<VertexPresentation, Point>();
		for (VertexPresentation vp : afterDragPositions.keySet()) {
			int x = vp.getCenter().x + start.x - end.x;
			int y = vp.getCenter().y + start.y - end.y;
			beforeDragPositions.put(vp, new Point(x, y));
		}
		oldLayout = new PredefinedLayout(beforeDragPositions);
		
		isFirstTime = true;
	}
	
	/**
	 * Creates new DragCommand.
	 * 
	 * @param beforeDragPositions
	 * @param graphPresentation 
	 * @param graphSelection 
	 */
	public DragCommand(Map<VertexPresentation, Point> beforeDragPositions, GraphPresentation graphPresentation, GraphElementSelection graphSelection) {
		this.graphSelection = graphSelection;
		this.graphPresentation = graphPresentation;
		
		afterDragPositions = new HashMap<VertexPresentation, Point>();
		for (VertexPresentation vp : graphSelection.getSelectedVertices()) {
			afterDragPositions.put(vp, vp.getCenter());
		}
		newLayout = new PredefinedLayout(afterDragPositions);
		isFirstTime = true;
		this.beforeDragPositions = beforeDragPositions;
		oldLayout = new PredefinedLayout(beforeDragPositions);
	}

	public void execute() {
		if (!isFirstTime) {
			graphSelection.unselect();
			graphPresentation.pauseFiringChanges();
			newLayout.performLayout();
			for (VertexPresentation vp : afterDragPositions.keySet()) {
				graphSelection.selectVertex(vp);
			}
		} else {
			isFirstTime = false;
		}
		graphPresentation.resumeFiringChanges();
	}

	public void undo() {
		graphPresentation.pauseFiringChanges();
		graphSelection.unselect();
		oldLayout.performLayout();
		for (VertexPresentation vp : beforeDragPositions.keySet()) {
			graphSelection.selectVertex(vp);
		}
		graphPresentation.resumeFiringChanges();
	}
}